package com.network.web.util;

import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

import javax.net.ssl.*;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
public class OkhttpAndRetrofitClientUtils {
    public static <T> T buildRetrofitClient(String inputUrl, Class<T> serviceClass) {
        return buildRetrofitClient(inputUrl, serviceClass, null);
    }

    public static <T> T buildRetrofitClientWithCertificate(String inputUrl, Class<T> inputClass, String certificatePath, String certificatePassword, String keyStoreType, String sslContextType) {
        OkHttpClient okHttpClient = OkhttpAndRetrofitClientUtils.buildOkHttpClientWithCertificate(certificatePath, certificatePassword, keyStoreType, sslContextType);

        return OkhttpAndRetrofitClientUtils.buildRetrofitClient(inputUrl, inputClass, okHttpClient);
    }

    public static <T> T buildRetrofitClient(String inputUrl, Class<T> serviceClass, OkHttpClient okHttpClient) {
        log.info("正在创建访问 {} 的RetrofitClient", inputUrl);
        Retrofit.Builder retrofitBuilder = new Retrofit.Builder();
        if (!Objects.isNull(okHttpClient)) {
            retrofitBuilder.client(okHttpClient);
        }
        Retrofit retrofit = retrofitBuilder.baseUrl(inputUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        return retrofit.create(serviceClass);
    }

    public static OkHttpClient buildOkHttpClientWithCertificate(String certificatePath, String certificatePassword, String keyStoreType, String sslContextType) {
        log.info("正在根据证书创建访问所需的 OkHttpClient");
        FileInputStream fis = FileUtils.fileToInputStreamByPath(certificatePath);
        OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();

        try {
            // 加载 PFX 证书
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);

            keyStore.load(fis, certificatePassword.toCharArray());

            // 初始化密钥管理器工厂，用于从密钥库中提取密钥
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, certificatePassword.toCharArray());

            // 初始化信任管理器工厂，用于从密钥库中提取受信任的证书
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);

            // 将平台信任的证书与PFX中的证书合并到自定义的信任管理器中
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            List<X509TrustManager> platformTrustManagers = Arrays.stream(trustManagers)
                    .filter(X509TrustManager.class::isInstance)
                    .map(X509TrustManager.class::cast)
                    .collect(Collectors.toList());

            X509TrustManager trustManager = new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    for (X509TrustManager platformTrustManager : platformTrustManagers) {
                        platformTrustManager.checkClientTrusted(chain, authType);
                    }
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//                    for (X509TrustManager platformTrustManager : platformTrustManagers) {
//                        platformTrustManager.checkServerTrusted(chain, authType);
//                    }
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    // 返回平台信任的证书
                    // 若想返回空证书 return new java.security.cert.X509Certificate[]{};
                    return platformTrustManagers.stream()
                            .flatMap(tm -> Arrays.stream(tm.getAcceptedIssuers()))
                            .toArray(X509Certificate[]::new);
                }
            };

            // 创建SSL上下文，使用初始化好的密钥管理器和自定义的信任管理器
            SSLContext sslContext = SSLContext.getInstance(sslContextType);
            sslContext.init(keyManagerFactory.getKeyManagers(), new TrustManager[]{trustManager}, null);

            // 配置OkHttpClient，使用上述SSL上下文创建的SSLSocketFactory
            okHttpBuilder.sslSocketFactory(sslContext.getSocketFactory(), trustManager);

            fis.close();
        } catch (Exception e) {
            log.error("根据证书创建okhttpClient失败原因为: {}", e.getMessage(), e);
            return null;
        }

        return okHttpBuilder.build();
    }
}
